package test.demo;

import com.alibaba.fastjson.JSON;
import tech.waterism.modelbase.PredictBase;
import tech.waterism.modelbase.PredictResult;

import java.io.IOException;
import java.util.*;

/**
 * 新安江模型（新安江产汇流）
 *
 * @author 潘晓健
 * @version 1.0
 * @date 2024-1-7
 */
public class SIMPLE extends PredictBase {

    //region Initial conditions, Parameters, Inputs, Statuses and Outputs

    //region Initial conditions for dunneMechanism

    /**
     * 产流系数
     */
    private double pr;

    /**
     * 基流率，单位mm/km²
     */
    private double kbase;

    /**
     * 面积，单位km²
     */
    private double area;

    /**
     * 径流出流系数
     */
    private double ku;

    /**
     * 径流滞时，单位是h
     */
    private double tu;

    /**
     * 降水时间
     */
    private Date[] floodTm;

    /**
     * 降水量
     */
    private double[] floodDrp;

    /**
     * 降水序列长度
     */
    private Integer floodRainRange;

    /**
     * 降水时段长
     */
    private double timeInterval;

    //endregion

    //region Outputs for dunneMechanism

    /**
     * 总产流
     */
    private double[] R;


    /**
     * 模拟分水源总产流
     */
    private double[] RunoffSim;

    //endregion

    //region Outputs for LinerReservoir

    /**
     * 坡面汇流-地表径流
     */
    private double[] Q;

    //endregion

    //endregion

    public SIMPLE(Map<String, String> data) {
        super();
        pr = Double.parseDouble(data.get("PR"));
        kbase = Double.parseDouble(data.get("Kbase"));
        area = Double.parseDouble(data.get("Area"));
        ku = Double.parseDouble(data.get("Ku"));
        tu = Double.parseDouble(data.get("Tu"));
        floodTm = JSON.parseObject(data.get("dt"), Date[].class);// input[i].data.dt
        floodDrp = JSON.parseObject(data.get("rain"), double[].class);// input[i].data.rain
        floodRainRange = floodDrp.length;
        timeInterval = Double.parseDouble(data.get("clen"));                  // index.clen
        RunoffSim = new double[floodRainRange];
        R = new double[floodRainRange];

        Q = new double[floodRainRange];
    }

    /**
     * 模型计算
     */
    public Map<String, double[]> SIMPLEModel() {

        //蓄满产流
        dunneMechanism();

        for (Integer j = 0; j < floodRainRange; j++) {
            RunoffSim[j] = R[j];
        }

        // 坡面汇流-线性水库
        overlandFlow();

        //河网汇流-滞后演算法,单元面积出口流量（m3/s）
        double[] QSim = timeLag();

        Map<String, double[]> simulationResult = new HashMap<>();
        simulationResult.put("rain", floodDrp);
        simulationResult.put("RSim", R);
        simulationResult.put("runoffSim", RunoffSim);
        simulationResult.put("QSim", QSim);
        return simulationResult;
    }


    /**
     * 蓄满产流模型
     *
     * @return 总产流、净雨
     */
    private void dunneMechanism() {
        for (Integer i = 0; i < floodRainRange; i++) {

            // R[i]为降雨乘以产流系数
            R[i] = floodDrp[i] * pr;

        }
    }



    /**
     * 坡面汇流
     *
     * @return 汇流
     */
    private void overlandFlow() {
        double a = kbase * area; // 每km2的基流量
        if(a < 0){
            a = 0;
        }
        double conversionFactor = area * 10 / 36 / timeInterval; // 妙立米换算系数

        for (Integer i = 0; i < floodRainRange; i++) {
            // Q[i]为汇流
            Q[i] = a + R[i] * conversionFactor;

        }
    }

    /**
     * 河网汇流
     * 滞时法
     *
     *
     * @return 河网汇流-单元面积出口流量（m3/s）
     */
    private double[] timeLag() {

        // 汇流 from LAG.dll
        double[] ssQ = new double[Q.length];

        for (int i = 1; i < ssQ.length; i++) {
            ssQ[i] = Q[i] * ku;
        }

        double a = 0;
        for (int i = 1; i < ssQ.length; i++) {
            a += Q[i];
            int j = i + (int) tu;
            if (j < ssQ.length) {
                ssQ[j] = a * ku;
            }
            a *= (1 - ku);
        }

        return ssQ;
    }

    private List<String> toStringList(double[] array0) {
        String[] array = new String[array0.length];
        for (int i = 0; i < array.length; i++) {
            array[i] = String.valueOf(array0[i]);
        }
        return Arrays.asList(array);
    }

    private List<String> toStringList(double[][] array0) {
        String[] array = new String[array0.length];
        for (int i = 0; i < array.length; i++) {
            array[i] = Arrays.toString(array0[i]);
        }
        return Arrays.asList(array);
    }

    @Override
    public void init() {

    }

    @Override
    public PredictResult predict() {
        PredictResult result = new PredictResult();
        Map<String, double[]> map = SIMPLEModel();

        double[][] RSim = new double[1][];
        //流域地表产流
        RSim[0] = map.get("RSim");

        //流域面积总产流，流域地表产流 RS[j] +  流域土壤产流RI[j] + 流域地下产流RG[j];
        result.setRunoffSim(map.get("runoffSim"));
        result.setRSim(RSim);
        //河道演进结果
        result.setQSim(map.get("QSim"));

        // 更新状态

        Map<String, List<String>> status = new HashMap<>();
        //上层张力水含量
        result.setNewStatus(status);
        return result;
    }

    public static void main(String[] args) throws IOException {

        // a. 模型参数 和 面平均降水数据
        //String a = "{\"B\":\"0.114\",\"EK\":\"0.797\",\"FC\":\"7.377\",\"IMP\":\"1.0\",\"KG\":\"0.53\",\"KU\":\"0.423\",\"TG\":\"4.703\",\"TU\":\"3.0\",\"WGM\":\"3.008\",\"WUM\":\"4.217\",\"KBASE\":\"0.002\",\"AREA\":\"11207.0\",\"clen\":\"1\",\"dt\":\"[\\\"2024-03-23 08:00:00\\\",\\\"2024-03-23 09:00:00\\\",\\\"2024-03-23 10:00:00\\\",\\\"2024-03-23 11:00:00\\\",\\\"2024-03-23 12:00:00\\\",\\\"2024-03-23 13:00:00\\\",\\\"2024-03-23 14:00:00\\\",\\\"2024-03-23 15:00:00\\\",\\\"2024-03-23 16:00:00\\\",\\\"2024-03-23 17:00:00\\\",\\\"2024-03-23 18:00:00\\\",\\\"2024-03-23 19:00:00\\\",\\\"2024-03-23 20:00:00\\\",\\\"2024-03-23 21:00:00\\\",\\\"2024-03-23 22:00:00\\\",\\\"2024-03-23 23:00:00\\\",\\\"2024-03-24 00:00:00\\\"]\",\"rain\":\"[10.0,0.0,0.2,0.8,2.0,5.0,8.0,8.0,8.0,2.0,0.2,0.0,0.0,0.0,0.0,0.0,0.0]\"}";
        String a = "{\"PR\":\"0.01\",\"Tu\":\"1\",\"Ku\":\"0.8\",\"Kbase\":\"0\",\"Area\":\"1756\",\"clen\":\"1\",\"dt\":\"[\\\"2024-03-23 08:00:00\\\",\\\"2024-03-23 09:00:00\\\",\\\"2024-03-23 10:00:00\\\",\\\"2024-03-23 11:00:00\\\",\\\"2024-03-23 12:00:00\\\",\\\"2024-03-23 13:00:00\\\",\\\"2024-03-23 14:00:00\\\",\\\"2024-03-23 15:00:00\\\",\\\"2024-03-23 16:00:00\\\",\\\"2024-03-23 17:00:00\\\",\\\"2024-03-23 18:00:00\\\",\\\"2024-03-23 19:00:00\\\",\\\"2024-03-23 20:00:00\\\",\\\"2024-03-23 21:00:00\\\",\\\"2024-03-23 22:00:00\\\",\\\"2024-03-23 23:00:00\\\",\\\"2024-03-24 00:00:00\\\"]\",\"rain\":\"[10.0,0.0,0.2,0.8,2.0,5.0,8.0,8.0,8.0,2.0,0.2,0.0,0.0,0.0,0.0,0.0,0.0]\"}";
        System.out.println(a);
        Map data = JSON.parseObject(a, Map.class);
        SIMPLE model = new SIMPLE(data);
        //List<TimeSeriesData> seriesData = model.seriesData;
        PredictResult result = model.predict();
        System.out.println(result);

    }

}